package org.numb.common.handler;

import static org.numb.common.i18n.ErrorCode.INTERNAL_ERROR_DEFAULT_MESSAGE;
import static org.numb.common.i18n.ErrorCode.INVALID_PARAMETERS_MESSAGE;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import org.apache.commons.lang3.StringUtils;
import org.numb.common.i18n.MessageProcessor;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@Component
@ControllerAdvice
public class GlobalExceptionHandler {

    @Resource
    private MessageProcessor messageProcessor;

    /**
     * BindException和MethodArgumentNotValidException异常，响应码为400
     *
     * @param request   http请求
     * @param exception 参数绑定异常
     * @return 异常响应国际化信息
     */
    @ExceptionHandler(value = {BindException.class, MethodArgumentNotValidException.class})
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public String handleBindException(HttpServletRequest request, BindException exception) {
        String message = "";
        String fieldName = "";
        // 从exception中获取参数名称fieldName
        if (exception.getBindingResult().getFieldError() != null) {
            String field = exception.getBindingResult().getFieldError().getField();
            if (StringUtils.isNotBlank(field)) {
                fieldName = field;
            }
        }
        if (exception.getBindingResult().getAllErrors().size() > 0) {
            message = exception.getBindingResult().getAllErrors().get(0).getDefaultMessage();
        }
        // 如果国际化消息为空，使用默认的国际化消息
        if (StringUtils.isBlank(message)) {
            message = messageProcessor.getMessage(request, INVALID_PARAMETERS_MESSAGE);
        }
        return String.format(message, fieldName);
    }

    /**
     * 处理ConstraintViolationException异常，响应400
     *
     * @param request   http请求
     * @param exception 参数绑定异常
     * @return 异常响应国际化信息
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.BAD_REQUEST)
    public String handleConstraintViolationException(HttpServletRequest request, ConstraintViolationException exception) {
//        String message = exception.getMessage();
//        Set<ConstraintViolation<?>> constraintViolations = exception.getConstraintViolations();
//        if (constraintViolations != null && constraintViolations.size() > 0) {
//            ConstraintViolation<?> next = constraintViolations.iterator().next();
//            message = next.getMessage();
//        }
//        if (StringUtils.isBlank(message)) {
//            message = messageProcessor.getMessage(request, INVALID_PARAMETERS_MESSAGE);
//        }
//        获取参数名
//        ConstraintViolation<?> violation = violations.iterator().next();
//        String path = ((PathImpl) violation.getPropertyPath()).getLeafNode().getName();
//        String message2 = String.format("%s:%s", path, violation.getMessage());
        return exception.getMessage();
    }

    /**
     * 处理其他未被捕获的异常，返回服务器内部错误，响应500
     *
     * @param request   http请求
     * @param exception 参数绑定异常
     * @return 异常响应国际化信息
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    public String handleException(HttpServletRequest request, Exception exception) {
        return messageProcessor.getMessage(request, INTERNAL_ERROR_DEFAULT_MESSAGE);
    }
}
